﻿// -----------------------------------------------------------------------
// <copyright file="RegexCharClass.cs" company="Microsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace FxCopContrib.Experimental.RegexCop
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.Text.RegularExpressions;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class RegexCharClass : PrivateReflectionWrapper
    {
        private static readonly Assembly RegexAssembly = typeof(Regex).Assembly;
        private const string RegexCharClassTypeFullName = "System.Text.RegularExpressions.RegexCharClass";
        private static readonly Type RegexCharClassType = RegexAssembly.GetType(RegexCharClassTypeFullName);

        internal RegexCharClass() : base(RegexCharClassType) { }
        internal RegexCharClass(object internalRegexCharClass) : base(RegexCharClassType, internalRegexCharClass) { }

        public bool Negate
        {
            get
            {
                return GetFieldValue<bool>("_negate");
            }
        }

        public IEnumerable<SingleRange> Ranges
        {
            get
            {
                return ToEnumerable<SingleRange>("_rangelist");
            }
        }

        public RegexCharClass Subtractor
        {
            get
            {
                object result = GetFieldValue<object>("_subtractor");
                if (result != null)
                {
                    return new RegexCharClass(result);
                }
                else
                {
                    return null;
                }
            }
        }

        //TODO: Convert to usable enumeration or similar
        private string _categories;
        public IEnumerable<char> Categories
        {
            get
            {
                if (_categories == null)
                {
                    StringBuilder builder = GetFieldValue<StringBuilder>("_categories");
                    if (builder != null)
                    {
                        _categories = builder.ToString();
                    }
                    else
                    {
                        _categories = string.Empty;
                    }
                }
                return _categories;
            }
        }

        public bool Contains(char c)
        {
            return CharInClass(c, ToStringClass());
        }

        private static bool CharInClass(char c, string set)
        {
            return (bool)RegexCharClassType.InvokeMember("CharInClass", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic, null, null, new object[] { c, set });
        }

        private string ToStringClass()
        {
            return (string)RegexCharClassType.InvokeMember("ToStringClass", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, null, wrappedObject, new object[] { });
        }

        public bool Intersects(RegexCharClass other)
        {
            //TODO implement
            return true;
        }

        internal static RegexCharClass FromChar(char c)
        {
            ConstructorInfo ci = RegexCharClassType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null);
            object regexCharClass = ci.Invoke(new object[]{});
            RegexCharClassType.InvokeMember("AddChar", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, regexCharClass, new object[]{c});
            if (regexCharClass != null)
            {
                return new RegexCharClass(regexCharClass);
            }
            else
            {
                return null;
            }
        }
        
        internal static RegexCharClass FromString(string str)
        {
            object regexCharClass = RegexCharClassType.InvokeMember("Parse", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { str });

            if (regexCharClass != null)
            {
                return new RegexCharClass(regexCharClass);
            }
            else
            {
                return null;
            }
        }
    }
}
